package com.mes.basicdata.domain;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.hibernate.annotations.BatchSize;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.ForeignKey;
import org.hibernate.annotations.Formula;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.JoinColumnOrFormula;
import org.hibernate.annotations.JoinColumnsOrFormulas;
import org.hibernate.annotations.JoinFormula;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
import org.hibernate.annotations.OrderBy;
import org.springframework.context.annotation.Lazy;

import com.mes.common.domain.BasicModel;

/**
 * <p>
 * 工序对象，在外部系统中有可能RoutingOperation和Operation是保存在一个系统中的，因此它们的Uid可能是一样的
 * </p>
 */
@Entity()
@org.hibernate.annotations.Entity(dynamicInsert=true,dynamicUpdate=true)
@Table(name = "B_ROUTINE")
@BatchSize(size=30)
@Lazy(value=true)
@Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Operation extends BasicModel {

	public final static String OPERATION_TYPE_NORMAL = "201"; // 普通工序
	public final static String OPERATION_TYPE_CHECK = "202"; // 检验工序
	public final static String OPERATION_TYPE_SAMPLE = "205"; // 试样工序
	
	public final static String OPERATION_TYPE_REF = "209"; // 参照工序
	
	@Override
	public String toString() {
		return "工序"+" "+getOperationIdDesc()+" "+getOperationName();
	}


	// 工序唯一号
	@Id
	@GenericGenerator(name = "operationUid", strategy = "assigned")
	@Column(name="UNIQUEID",scale=0)
	private String uniqueId;
	
	// 工序号
	@Column(name="OPERATION_IDDESC")
	private String operationIdDesc;
	
	// 工序名称
	@Column(name="OPERATION_NAME")
	private String operationName;
	
	// 详细内容
	@Column(name="OPERATION_CONTENT")
	private String operationContent;
	
	// 简化内容
	@Column(name="OPERATION_SIMPLE_CONTENT")
	private String operationSimpleContent;
	
	// 工作中心编号
	@Column(name="MACHINE_NUMBER")
	private String workCenterUid;
	
	@ForeignKey(name="null")
	@ManyToOne(fetch=FetchType.LAZY,cascade=CascadeType.PERSIST)
	@JoinColumn(name="MACHINE_NUMBER",insertable=false,updatable=false)
	private WorkCenter workCenter;
	
	//设备类编号
	@Column(name="BASE_MACHINE_RESOURCE")
	private String deviceClassUid;
	
	@ForeignKey(name="null")
	@ManyToOne(fetch=FetchType.LAZY,cascade=CascadeType.PERSIST)
	@JoinColumn(name="BASE_MACHINE_RESOURCE",insertable=false,updatable=false)
	private DeviceClass deviceClass;
	
	//加工部门
	@Column(name="DEPTID")
	private String deptUid;
	@ForeignKey(name="null")
	@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumn(name="DEPTID",referencedColumnName="DEPTID",insertable=false,updatable=false)
	private Dept dept;

	
	// 是否有效
	@Column(name="EFFECTIVE" ,precision=2,scale=0)
	private Boolean isEffective;
	
	// 工序组
	@Column(name="OPERATION_GROUP")
	private String operationGroup;

	@Column(name="PREPAREGRADE", precision=2,scale=0)
	private Integer prepareGrade;

	// 是否可以并行加工
	@Column(name="PARALLEL",precision=10,scale=0)
	private Boolean isParallel;
	
	// 并行最小数量
	@Column(name="PARALLEL_THRESHOLD",length=10)
	private Float parallelThresholdQty;
	
	// 转运批次数量
	@Column(name="TRANSFER_BATCH_QUANTITY" ,precision=10,scale=0)
	private Float transferBatchQty;
	
	// 单件产出比
	@Column(name="BASE_YIELD" ,precision=10,scale=5)
	private Float baseYield;

	// 工序类型
	@Column(name="OPERATION_TYPE" ,precision=10,scale=0)
	private String operationType;
	
	/*@ForeignKey(name="null")
//	@NotFound(action=NotFoundAction.IGNORE)
	@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumnsOrFormulas(value={
			@JoinColumnOrFormula(column=@JoinColumn(name="OPERATION_TYPE",referencedColumnName="ID",nullable=true,insertable=false,updatable=false)),
			@JoinColumnOrFormula(formula=@JoinFormula(value="'tasktype'", referencedColumnName="TYPESNAME"))
	})
	private TypesData operationTypeDesc;*/
	
	// 工种类型
	@Column(name="OPTYPE", precision=10,scale=0)
	private Integer opType;
	/*@ForeignKey(name="null")
	@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumnsOrFormulas(value={
			@JoinColumnOrFormula(column=@JoinColumn(name="OPTYPE",referencedColumnName="ID",nullable=true,insertable=false,updatable=false)),
			@JoinColumnOrFormula(formula=@JoinFormula(value="'optype'", referencedColumnName="TYPESNAME"))
	})
//	@NotFound(action=NotFoundAction.IGNORE)
	private TypesData opTypeDesc;*/
	
	// 是否需要首件三检
	@Column(name="NEED_FIRSTCHECK" ,precision=1, scale=0)
	private Boolean isNeedFirstCheck;
	
	// 是否需要检验
	@Column(name="NEED_CHECK",precision=10,scale=0)
	private Boolean isNeedCheck;
	
	// 抽检验百分比
	@Column(name="CHECKPERCENT" ,precision=10)
	private Float checkPercent;
	
	// 是否关键
	@Column(name="IS_CRITICAL_OPERATION",precision=10,scale=0)
	private Boolean isCritical;
	
//	// 是否是特殊工序
//	@Column(name="IS_SPECIAL_OPERATION",precision=10,scale=0)
//	private Boolean isSpecial;
	
//	// 是否需要物料检入
//	@Column(name="MATERIAL_CHECK_IN" ,precision=10,scale=0)
//	private Boolean isNeedCheckIn;
//	
//	// 是否需要物料检出
//	@Column(name="MATERIAL_CHECK_OUT" ,precision=10,scale=0)
//	private Boolean isNeedCheckOut;
	
//	// 工序总成本
//	@Column(name="OPERATION_COST_SUM", precision=10,scale=0)
//	private Float totalCost;
	
//	// 人力成本
//	@Column(name="LABOR_COST" ,precision=10,scale=0)
//	private Float laborCost;
//	
//	// 设备成本
//	@Column(name="MACHINE_COST" ,precision=10,scale=0)
//	private Float machineCost;
	
	// 工时系数
	@Column(name="WORKCOEFFICIENT", precision=25,scale=6)
	private Float workCoefficient;

	// 分派等级
	@Column(name="DISPATCHGRADE",precision=10,scale=0)
	private Integer dispatchGrade;
	
	// 需要试样
	@Column(name="NEED_SAMPLE", precision=2,scale=0)
	private Boolean isNeedSample;

	// 试样数量
	@Column(name="SAMPLEQTY" ,precision=5,scale=0)
	private Float sampleQty;
	
	// 试样百分比
	@Column(name="SAMPLEPERCENT",precision=5)
	private Float samplePercent;
	
	// 样品单件运行时间
	@Column(name="SAMPLE_RUNTIME" ,precision=12)
	private Float sampleRunTime;
	
	// 准备时间--定额
	@Column(name="PREOP_TIME",precision=12)
	private Float preOpTime;
	
	// 单件运行时间--定额
	@Column(name="UNIT_RUNTIME",precision=12)
	private Float runTime;
	
	// 卸载时间--定额
	@Column(name="POSTOP_TIME",precision=12)
	private Float postOpTime;
	
	// 估计装备时间
	@Column(name="ESTIPRETIME")
	private Float estiPreOpTime;
	
	// 估计运行时间
	@Column(name="ESTIRUNTIME")
	private Float estiRunTime;
	
	// 估计结束时间
	@Column(name="ESTIPOSTOPTIME")
	private Float estiPostOpTime;
	
//	// 估计延搁时间
//	@Column(name="OP_ESTIMATED_QUENE_TIME")
//	private Float estiDelayTime;
	
//	// 最大工期
//	@Column(name="MIN_OPERATION_TIME")
//	private Float maxDuration;

//	//加密字符串
//	// 估计装备时间，加密
//	private String encryptEstiPreopTime;
//	// 估计运行时间，加密
//	private String encryptEstiRunTime;
//	// 估计结束时间,加密
//	private String encryptEstiPostopTime;

//	// 样品工序号
//	@Column(name="SAMPLE_OPID" ,length=50)
//	private String sampleOperationUid;
	
	// 工艺与工序的关联关系
	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "operation")
	private Set<RoutingOperation> routingOperations;
	
	// 工序物料
	@OneToMany(fetch=FetchType.LAZY, mappedBy = "operation")
	@OrderBy(clause="createTime asc")
	private Set<OperationPart> operationParts;
	// 工序资源
	@OneToMany(fetch=FetchType.LAZY, mappedBy = "operation")
	//@OrderBy(clause="createTime asc")
	private Set<OperationResource> operationResources;
	//工序设备
	@OneToMany(fetch=FetchType.LAZY, mappedBy = "operation")
	@OrderBy(clause="createTime asc")
	private Set<OperationDevice> operationDevices;
	
	// 工序用到的刀具
	private transient Set<Cutter> cutters = new HashSet<Cutter>(0);
	// 工序用到的卡具
	private transient Set<Clamp> clamps = new HashSet<Clamp>(0);
	// 工序用到的量具
	private transient Set<Measurer> measurers = new HashSet<Measurer>(0);
	
	// 工序检验信息
	@OneToMany(fetch=FetchType.LAZY, mappedBy = "operation")
	private  Set<OperationMeasurement> operationMeasurements = new HashSet<OperationMeasurement>(0);

	// 子工艺参照唯一号
	@Column(name="REFROUTING")
	private String refRoutingUid;
	//many-to-one
	@ForeignKey(name="null")
	@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumn(name="REFROUTING",referencedColumnName="ROUTING",insertable=false,updatable=false)
	private Routing refRouting;
	
//	@Formula("(select count(*) from b_bill_of_materials b where b.opuid=UNIQUEID)")
//	private Integer partCount;
//	
//	@Formula("(select count(*) from b_operation_resource bo where bo.opuid=UNIQUEID)")
//	private Integer resourceCount;

	private Float operationId;
	
	//父工步
	@Column(name="PARENTOPUID")
	private String parentOpUid;
	
	public String getParentOpUid() {
		return parentOpUid;
	}

	public void setParentOpUid(String parentOpUid) {
		this.parentOpUid = parentOpUid;
	}

	public String getUniqueId() {
		return uniqueId;
	}

	public void setUniqueId(String uniqueId) {
		this.uniqueId = uniqueId;
	}
	
	@Override
	public String getUuid() {
		// TODO Auto-generated method stub
		return this.getUniqueId();
	}

	@Override
	public void setUuid(String uuid) {
		// TODO Auto-generated method stub
		this.setUniqueId(uuid);
	}
	
    public Set<RoutingOperation> getRoutingOperations() {
		return routingOperations;
	}
	public void setRoutingOperations(Set<RoutingOperation> routingOperations) {
		this.routingOperations=routingOperations;
	}
	
	public String getOperationIdDesc() {
		return operationIdDesc;
	}

	public void setOperationIdDesc(String operationIdDesc) {
		this.operationIdDesc = operationIdDesc;
	}

	public String getOperationName() {
		return operationName;
	}

	public void setOperationName(String operationName) {
		this.operationName = operationName;
	}

	public String getOperationContent() {
		return operationContent;
	}

	public void setOperationContent(String operationContent) {
		this.operationContent = operationContent;
	}

	public String getOperationSimpleContent() {
		return operationSimpleContent;
	}

	public void setOperationSimpleContent(String operationSimpleContent) {
		this.operationSimpleContent = operationSimpleContent;
	}

	public String getWorkCenterUid() {
		return workCenterUid;
	}

	public void setWorkCenterUid(String workCenterUid) {
		this.workCenterUid = workCenterUid;
	}

	public WorkCenter getWorkCenter() {
		return workCenter;
	}

	public void setWorkCenter(WorkCenter workCenter) {
		this.workCenter = workCenter;
	}

	public String getDeviceClassUid() {
		return deviceClassUid;
	}

	public void setDeviceClassUid(String deviceClassUid) {
		this.deviceClassUid = deviceClassUid;
	}

	public DeviceClass getDeviceClass() {
		return deviceClass;
	}

	public void setDeviceClass(DeviceClass deviceClass) {
		this.deviceClass = deviceClass;
	}

	public String getDeptUid() {
		return deptUid;
	}

	public void setDeptUid(String deptUid) {
		this.deptUid = deptUid;
	}

	public Dept getDept() {
		return dept;
	}

	public void setDept(Dept dept) {
		this.dept = dept;
	}

	public Boolean getIsEffective() {
		return isEffective;
	}

	public void setIsEffective(Boolean isEffective) {
		this.isEffective = isEffective;
	}

	public String getOperationGroup() {
		return operationGroup;
	}

	public void setOperationGroup(String operationGroup) {
		this.operationGroup = operationGroup;
	}

	public Integer getPrepareGrade() {
		return prepareGrade;
	}

	public void setPrepareGrade(Integer prepareGrade) {
		this.prepareGrade = prepareGrade;
	}

	public Boolean getIsParallel() {
		return isParallel;
	}

	public void setIsParallel(Boolean isParallel) {
		this.isParallel = isParallel;
	}

	public Float getParallelThresholdQty() {
		return parallelThresholdQty;
	}

	public void setParallelThresholdQty(Float parallelThresholdQty) {
		this.parallelThresholdQty = parallelThresholdQty;
	}

	public Float getTransferBatchQty() {
		return transferBatchQty;
	}

	public void setTransferBatchQty(Float transferBatchQty) {
		this.transferBatchQty = transferBatchQty;
	}

	public Float getBaseYield() {
		return baseYield;
	}

	public void setBaseYield(Float baseYield) {
		this.baseYield = baseYield;
	}

	public String getOperationType() {
		return operationType;
	}

	public void setOperationType(String operationType) {
		this.operationType = operationType;
	}

	public Integer getOpType() {
		return opType;
	}

	public void setOpType(Integer opType) {
		this.opType = opType;
	}

	public Boolean getIsNeedFirstCheck() {
		return isNeedFirstCheck;
	}

	public void setIsNeedFirstCheck(Boolean isNeedFirstCheck) {
		this.isNeedFirstCheck = isNeedFirstCheck;
	}

	public Boolean getIsNeedCheck() {
		return isNeedCheck;
	}

	public void setIsNeedCheck(Boolean isNeedCheck) {
		this.isNeedCheck = isNeedCheck;
	}

	public Float getCheckPercent() {
		return checkPercent;
	}

	public void setCheckPercent(Float checkPercent) {
		this.checkPercent = checkPercent;
	}

	public Boolean getIsCritical() {
		return isCritical;
	}

	public void setIsCritical(Boolean isCritical) {
		this.isCritical = isCritical;
	}

	public Float getWorkCoefficient() {
		return workCoefficient;
	}

	public void setWorkCoefficient(Float workCoefficient) {
		this.workCoefficient = workCoefficient;
	}

	public Integer getDispatchGrade() {
		return dispatchGrade;
	}

	public void setDispatchGrade(Integer dispatchGrade) {
		this.dispatchGrade = dispatchGrade;
	}

	public Boolean getIsNeedSample() {
		return isNeedSample;
	}

	public void setIsNeedSample(Boolean isNeedSample) {
		this.isNeedSample = isNeedSample;
	}

	public Float getSampleQty() {
		return sampleQty;
	}

	public void setSampleQty(Float sampleQty) {
		this.sampleQty = sampleQty;
	}

	public Float getSamplePercent() {
		return samplePercent;
	}

	public void setSamplePercent(Float samplePercent) {
		this.samplePercent = samplePercent;
	}

	public Float getSampleRunTime() {
		return sampleRunTime;
	}

	public void setSampleRunTime(Float sampleRunTime) {
		this.sampleRunTime = sampleRunTime;
	}

	public Float getPreOpTime() {
		return preOpTime;
	}

	public void setPreOpTime(Float preOpTime) {
		this.preOpTime = preOpTime;
	}

	public Float getRunTime() {
		return runTime;
	}

	public void setRunTime(Float runTime) {
		this.runTime = runTime;
	}

	public Float getPostOpTime() {
		return postOpTime;
	}

	public void setPostOpTime(Float postOpTime) {
		this.postOpTime = postOpTime;
	}

	public Float getEstiPreOpTime() {
		return estiPreOpTime;
	}

	public void setEstiPreOpTime(Float estiPreOpTime) {
		this.estiPreOpTime = estiPreOpTime;
	}

	public Float getEstiRunTime() {
		return estiRunTime;
	}

	public void setEstiRunTime(Float estiRunTime) {
		this.estiRunTime = estiRunTime;
	}

	public Float getEstiPostOpTime() {
		return estiPostOpTime;
	}

	public void setEstiPostOpTime(Float estiPostOpTime) {
		this.estiPostOpTime = estiPostOpTime;
	}

	public Set<OperationPart> getOperationParts() {
		return operationParts;
	}

	public void setOperationParts(Set<OperationPart> operationParts) {
		this.operationParts = operationParts;
	}

	public Set<OperationResource> getOperationResources() {
		return operationResources;
	}

	public void setOperationResources(Set<OperationResource> operationResources) {
		this.operationResources = operationResources;
	}

	public Set<OperationDevice> getOperationDevices() {
		return operationDevices;
	}

	public void setOperationDevices(Set<OperationDevice> operationDevices) {
		this.operationDevices = operationDevices;
	}

	public Routing getRefRouting() {
		return refRouting;
	}

	public void setRefRouting(Routing refRouting) {
		this.refRouting = refRouting;
	}

	public String getRefRoutingUid() {
		return refRoutingUid;
	}

	public Set<OperationMeasurement> getOperationMeasurements() {
		return operationMeasurements;
	}

	public void setOperationMeasurements(Set<OperationMeasurement> operationMeasurements) {
		this.operationMeasurements = operationMeasurements;
	}

	public void setRefRoutingUid(String refRoutingUid) {
		this.refRoutingUid = refRoutingUid;
	}

//	@Formula("(select count(*) from f_file_field fff where fff.fielduid=to_char(UNIQUEID) and fff.fieldType='OPERATION_NC_FILE')")
//	private Integer ncFileCount;
	
//	// 工序卡数量
//	@Formula("(select count(*) from f_file_field fff where fff.fielduid=to_char(UNIQUEID)  and fff.fieldType='OPERATION_FILE')")
//	protected Integer cardFileCount;
	
//	/**
//	 * 工时管理员的备注
//	 */
//	@Column(name="ROUTING_NOTE")
//	private String manHourNotes;
	

//	/**
//	 * add by zy 
//	 * 2016-07-12
//	 * 批量与工时
//	 */
//	@Column(name="PROCESS_BATCH_QUANTITY",precision=10,scale=0)
//	public Float processBatchQty;
//	
//	@Column(name="PROCESS_BATCH_RUNTIME",precision=10,scale=0)
//	public Float processBatchRunTime;
	
	


	public Set<Cutter> getCutters() {//throws BaseDBException {
		if (cutters.size() == 0 && clamps.size() == 0 && measurers.size() == 0) {
			Set<OperationResource> ors = this.getOperationResources();
			Set<Cutter> cuttersTemp = new HashSet<Cutter>(0);
			Set<Clamp> clampsTemp = new HashSet<Clamp>(0);
			Set<Measurer> measurersTemp = new HashSet<Measurer>(0);
			Iterator<OperationResource> iter = ors.iterator();
			OperationResource temp;
			while (iter.hasNext()) {
				temp = iter.next();
				if (temp.isCutter()) {
					cuttersTemp.add(temp.getCutter());
				} else if (temp.isClamp()) {
					clampsTemp.add(temp.getClamp());
				} else if (temp.isMeasurer()) {
					measurersTemp.add(temp.getMeasurer());
				}
			}
			cutters = cuttersTemp;
			clamps = clampsTemp;
			measurers = measurersTemp;
		}
		return cutters;
	}

	public void setCutters(Set<Cutter> cutters) {
		this.cutters = cutters;
	}

	public Set<Clamp> getClamps() {//throws BaseDBException {
		if (cutters.size() == 0 && clamps.size() == 0 && measurers.size() == 0) {
			Set<OperationResource> ors = this.getOperationResources();
			Set<Cutter> cuttersTemp = new HashSet<Cutter>(0);
			Set<Clamp> clampsTemp = new HashSet<Clamp>(0);
			Set<Measurer> measurersTemp = new HashSet<Measurer>(0);
			Iterator<OperationResource> iter = ors.iterator();
			OperationResource temp;
			while (iter.hasNext()) {
				temp = iter.next();
				if (temp.isCutter()) {
					cuttersTemp.add(temp.getCutter());
				} else if (temp.isClamp()) {
					clampsTemp.add(temp.getClamp());
				} else if (temp.isMeasurer()) {
					measurersTemp.add(temp.getMeasurer());
				}
			}
			cutters = cuttersTemp;
			clamps = clampsTemp;
			measurers = measurersTemp;
		}
		return clamps;
	}

	public void setClamps(Set<Clamp> clamps) {
		this.clamps = clamps;
	}

	/**
	 * @return the measures
	 */
	public Set<Measurer> getMeasurers() {//throws BaseDBException {
		if (cutters.size() == 0 && clamps.size() == 0 && measurers.size() == 0) {
			Set<OperationResource> ors = this.getOperationResources();
			Set<Cutter> cuttersTemp = new HashSet<Cutter>(0);
			Set<Clamp> clampsTemp = new HashSet<Clamp>(0);
			Set<Measurer> measurersTemp = new HashSet<Measurer>(0);
			Iterator<OperationResource> iter = ors.iterator();
			OperationResource temp;
			while (iter.hasNext()) {
				temp = iter.next();
				if (temp.isCutter()) {
					cuttersTemp.add(temp.getCutter());
				} else if (temp.isClamp()) {
					clampsTemp.add(temp.getClamp());
				} else if (temp.isMeasurer()) {
					measurersTemp.add(temp.getMeasurer());
				}
			}
			cutters = cuttersTemp;
			clamps = clampsTemp;
			measurers = measurersTemp;
		}
		return measurers;
	}

	public void setMeasurers(Set<Measurer> measurers) {
		this.measurers = measurers;
	}

	public Float getOperationId() {
		return operationId;
	}
	public void setOperationId(Float operationId) {
		this.operationId = operationId;
	}

	private String mmen(Integer number) {
		SimpleDateFormat myFormat = new SimpleDateFormat("HHmmss");
		String tempString = myFormat.format(new Date());
		tempString += Integer.toString(number);
		char[] charArray = tempString.toCharArray();
		String temp = "";
		for (int i = 0; i < charArray.length; i++) {
			temp += Integer.toHexString((int) charArray[i]);
		}
		while (temp.length() < 42) {
			temp += "0";
		}
		return temp;
	}

	private long mmdn(String str) {
		String temp = str.substring(12);
		String strTemp = "";
		for (int i = 0; i < 30; i += 2) {
			if (temp.substring(i, i + 2).equals("00"))
				break;
			strTemp += temp.charAt(i + 1);
		}
		return Integer.valueOf(strTemp);
	}


	public int compareTo(Object o) {
		if (!(o instanceof Operation)) {
			return 1;
		}
		Operation node = (Operation) o;
		if (this.getOperationId() == null && node.getOperationId() != null) {
			return -1;
		} else if (this.getOperationId() != null
				&& node.getOperationId() == null) {
			return 1;
		} else if (this.getOperationId() == null
				&& node.getOperationId() == null) {
			return 0;
		} else {
			return this.getOperationId().compareTo((node.getOperationId()));
		}
	}
	
}